using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace C4F.DevKit.Messaging
{
    /// <summary>
    /// Imports functionalities from native API.
    /// </summary>
    internal class MapiManagementNative
    {
        #region DllImports

        [DllImport("mapi32.dll")]
        [return: MarshalAs(UnmanagedType.Error)]
        internal static extern Int32 MAPIInitialize(IntPtr lpMapiInit);

        [return: MarshalAs(UnmanagedType.Error)]
        [DllImport("mapi32.dll")]
        internal static extern Int32 MAPIAdminProfiles(Int32 i, out IProfAdmin a);

        [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
        internal static extern int MAPILogon(IntPtr handle, string profileName,
        string password, int flag, int reserved, ref IntPtr session);

        [DllImport("MAPI32.DLL")]
        internal static extern int MAPILogoff(IntPtr session, IntPtr handle,
        int flag, int reserved);

        [DllImport("MAPI32.DLL")]
        internal static extern int MAPISendMail(IntPtr session, IntPtr handle,
        MapiMessage message, int flag, int reserved);

        [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
        internal static extern int MAPIFindNext(IntPtr session, IntPtr handle, string typ,
        string seed, int flag, int reserved, StringBuilder id);

        [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
        internal static extern int MAPIReadMail(IntPtr session, IntPtr handle, string id,
        int flag, int reserved, ref IntPtr ptrmsg);

        [DllImport("MAPI32.DLL")]
        internal static extern int MAPIFreeBuffer(IntPtr ptr);

        [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
        internal static extern int MAPIDeleteMail(IntPtr session, IntPtr handle, string id,
        int flag, int reserved);

        #endregion

        #region InterfaceImports

        /// <summary>
        /// .Net wrapper over IMAPITable interface.
        /// </summary>
        [Guid("00020301-0000-0000-c000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IMAPITable
        {
            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 GetLastError([In][MarshalAs(UnmanagedType.Error)]Int32 hResult,
            [In][MarshalAs(UnmanagedType.U4)] UInt32 ulFlags,
            [Out][MarshalAs(UnmanagedType.LPStruct)]IntPtr lppMAPIError);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 Advise([In][MarshalAs(UnmanagedType.U4)]UInt32 ulEventMask,
            IntPtr lpAdviseSink,
            IntPtr lpulConnection);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 Advise([In][MarshalAs(UnmanagedType.U4)]UInt32 ulConnection);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 GetStatus(IntPtr lpulTableStatus,
            IntPtr lpulTableType);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 SetColumns(
            out  IntPtr lpPropTagArray,
            [In][MarshalAs(UnmanagedType.U4)] UInt32 ulFlags);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 QueryColumns([In][MarshalAs(UnmanagedType.U4)]UInt32 ulFlags,
            IntPtr lpPropTagArray);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 GetRowCount([In][MarshalAs(UnmanagedType.U4)]UInt32 ulFlags,
            out UInt32 lpulCount);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 SeekRow(IntPtr bkOrigin,
            [In][MarshalAs(UnmanagedType.U4)]UInt32 lRowCount,
            IntPtr lplRowsSought);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 SeekRowApprox([In][MarshalAs(UnmanagedType.U4)]UInt32 ulNumerator,
            [In][MarshalAs(UnmanagedType.U4)]UInt32 ulDenominator);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 QueryPosition(IntPtr lpulRow,
            IntPtr lpulNumerator,
            IntPtr lpulDenominator);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 FindRow(
            out IntPtr lpRestriction,
            UInt32 BkOrigin,
            [In][MarshalAs(UnmanagedType.U4)]UInt32 ulFlags);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 Restrict(
            out IntPtr lpRestriction,
            [In][MarshalAs(UnmanagedType.U4)]UInt32 ulFlags);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 CreateBookmark(IntPtr lpbkPosition);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 FreeBookmark(IntPtr bkPosition);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 SortTable(IntPtr lpSortCriteria,
            [In][MarshalAs(UnmanagedType.U4)]UInt32 ulFlags);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 QuerySortOrder(IntPtr lppSortCriteria);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 QueryRows(
            UInt32 lRowCount,
            UInt32 ulFlags,
            out IntPtr lppRows);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 Abort();

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 ExpandRow([In][MarshalAs(UnmanagedType.U4)]UInt32 cbInstanceKey,
            IntPtr pbInstanceKey,
            [In][MarshalAs(UnmanagedType.U4)]UInt32 ulRowCount,
            [In][MarshalAs(UnmanagedType.U4)]UInt32 ulFlags,
            IntPtr lppRows,
            IntPtr lpulMoreRows);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 CollapseRow([In][MarshalAs(UnmanagedType.U4)]UInt32 cbInstanceKey,
            IntPtr pbInstanceKey,
            [In][MarshalAs(UnmanagedType.U4)]UInt32 ulFlags,
            IntPtr lpulRowCount);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 WaitForCompletion([In][MarshalAs(UnmanagedType.U4)]UInt32 ulFlags,
            [In][MarshalAs(UnmanagedType.U4)]UInt32 ulTimeout,
            IntPtr lpulTableStatus);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 GetCollapseState([In][MarshalAs(UnmanagedType.U4)]UInt32 ulFlags,
            [In][MarshalAs(UnmanagedType.U4)]UInt32 cbInstanceKey,
            IntPtr lpbInstanceKey,
            IntPtr lpcbCollapseState,
            IntPtr lppbCollapseState);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 SetCollapseState([In][MarshalAs(UnmanagedType.U4)]UInt32 ulFlags,
            [In][MarshalAs(UnmanagedType.U4)]UInt32 cbCollapseState,
            IntPtr pbCollapseState,
            IntPtr lpbkLocation);

        }

        /// <summary>
        /// .Net wrapper over IProfAdmin interface.
        /// </summary>
        [Guid("0002031c-0000-0000-c000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IProfAdmin
        {
            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 GetLastError([In][MarshalAs(UnmanagedType.Error)]Int32 hResult,
            [In][MarshalAs(UnmanagedType.U4)] UInt32 ulFlags,
            [Out][MarshalAs(UnmanagedType.LPStruct)]IntPtr lppMAPIError);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 GetProfileTable([In][MarshalAs(UnmanagedType.U4)] UInt32 ulFlags, [Out] out IMAPITable lppTable);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 CreateProfile(IntPtr lpszProfileName, IntPtr lpszPassword, IntPtr ulUIParam, UInt32 ulFlags);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 DeleteProfile(IntPtr lpszProfileName, UInt32 ulFlags);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 ChangeProfilePassword(
            [In][MarshalAs(UnmanagedType.LPWStr)]string lpszProfileName,
            [In][MarshalAs(UnmanagedType.LPWStr)] string lpszOldPassword,
            [In][MarshalAs(UnmanagedType.LPWStr)] string lpszNewPassword,
            [In][MarshalAs(UnmanagedType.U4)] UInt32 ulFlags);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 CopyProfile(
            IntPtr lpszOldProfileName,
            IntPtr lpszOldPassword,
            IntPtr lpszNewProfileName,
            IntPtr ulUIParam,
            IntPtr ulFlags);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 RenameProfile(
            IntPtr lpszOldProfileName,
            IntPtr lpszOldPassword,
            IntPtr lpszNewProfileName,
            IntPtr ulUIParam,
            IntPtr ulFlags);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 SetDefaultProfile(
            IntPtr lpszProfileName,
            UInt32 ulFlags);

            [PreserveSig]
            [return: MarshalAs(UnmanagedType.Error)]
            Int32 AdminServices(
            [In][MarshalAs(UnmanagedType.LPWStr)]string lpszProfileName,
            [In][MarshalAs(UnmanagedType.LPWStr)]string lpszPassword,
            [In][MarshalAs(UnmanagedType.U4)] UInt32 ulUIParam,
            [In][MarshalAs(UnmanagedType.U4)] UInt32 ulFlags,
            [Out][MarshalAs(UnmanagedType.IUnknown)] IntPtr lppServiceAdmin);

        }

        #endregion

        #region Classes and Structures

        #region Message Classes

        /// <summary>
        /// .Net wrapper over MapiMessage native structure.
        /// </summary>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        internal class MapiMessage
        {
            public int reserved;
            public string subject;
            public string messageBody;
            //IPM or non- IPM Interpersonal Message.
            public string messageType;
            public string dateReceived;
            public string conversationID;
            public int flags;
            public IntPtr originator;
            public int recipientCount;
            public IntPtr recipients;
            public int fileCount;
            public IntPtr files;
        }

        /// <summary>
        /// .Net wrapper over MapiRecipDesc native structure.
        /// </summary>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        internal class MapiRecipDesc
        {
            public int reserved;
            public int recipientClass;
            public string name;
            public string address;
            public int eIDSize;
            public IntPtr entryID;
        }

        /// <summary>
        /// .Net wrapper over MapiFileDesc native structure.
        /// </summary>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        internal class MapiFileDesc
        {
            public int reserved;
            public int flags;
            public int position;
            public string pathName;
            public string fileName;
            public IntPtr fileType;
        }

        #endregion

        #region Profile Structures


        /// <summary>
        /// .Net wrapper over SRowSet native structure.
        /// </summary>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        internal struct RowSet
        {
            // Count of rows.
            public UInt32 countRows;

            // Array of rows.
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
            public Row[] row;
	
        };

        /// <summary>
        /// .Net wrapper over SRow native structure.
        /// </summary>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        internal struct Row
        {
            // Pad so SRow's can map to ADRENTRY's.
            public UInt32 ulAdrEntryPad;

            // Count of property values.
            public UInt32 cValues;

            //Property value array.
            public PropValue lpProps;		

        } ;

        /// <summary>
        /// .Net wrapper over SPropValue native structure.
        /// </summary>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        internal struct PropValue
        {
            public UInt32 ulPropTag;
            public UInt32 dwAlignPad;
            public PropertyValue Value;
        } ;

        /// <summary>
        /// .Net wrapper over SPropertyValue native union.
        /// </summary>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        internal struct PropertyValue
        {
            public Int16 i;
            public Int32 l;
            public UInt32 ul;
            public Single flt;
            public Double dbl;
            public UInt16 b;
            public Single cur;
            public Double at;
            public System.Runtime.InteropServices.ComTypes.FILETIME ft;
            public string lpszA;
            public IntPtr bin;
            public string lpszW;

            #region Commented because of known issue of GetAvailableProfiles
            //public IntPtr lpguid;		/* case PT_CLSID */
            //public Int64 li;			/* case PT_I8 */
            //public IntPtr MVi;		/* case PT_MV_I2 */
            //public IntPtr MVl;		/* case PT_MV_LONG */
            //public IntPtr MVflt;		/* case PT_MV_R4 */
            //public IntPtr MVdbl;		/* case PT_MV_DOUBLE */
            //public IntPtr MVcur;		/* case PT_MV_CURRENCY */
            //public IntPtr MVat;		/* case PT_MV_APPTIME */
            //public IntPtr MVft;		/* case PT_MV_SYSTIME */
            //public IntPtr MVbin;		/* case PT_MV_BINARY */
            //public IntPtr MVszA;		/* case PT_MV_STRING8 */
            //public IntPtr MVszW;		/* case PT_MV_UNICODE */
            //public IntPtr MVguid;		/* case PT_MV_CLSID */
            //public IntPtr MVli;		/* case PT_MV_I8 */
            //public IntPtr err;		/* case PT_ERROR */
            // public Int32 x;			/* case PT_NULL, PT_OBJECT (no usable value) */
            #endregion
        } ;

        #endregion

        #endregion
    }
}
